/*
    Dao FLTK2
    Copyright (C) 2010 Belousov Oleg <belousov.oleg@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <GL/glu.h>
#include <fltk/gl.h>
#include <dao.h>

#include "gl.h"

static void glbegin(DaoContext *ctx, DValue *p[], int N) {
    glBegin(p[0]->v.i);
}

static void glend(DaoContext *ctx, DValue *p[], int N) {
    glEnd();
}

static void glcolor(DaoContext *ctx, DValue *p[], int N) {
    glColor3f(p[0]->v.f, p[1]->v.f, p[2]->v.f);
}

static void glvertex(DaoContext *ctx, DValue *p[], int N) {
    glVertex3f(p[0]->v.f, p[1]->v.f, p[2]->v.f);
}

static void glviewport(DaoContext *ctx, DValue *p[], int N) {
    glViewport(p[0]->v.f, p[1]->v.f, p[2]->v.f, p[3]->v.f);
}

static void glortho(DaoContext *ctx, DValue *p[], int N) {
    glOrtho(p[0]->v.f, p[1]->v.f, p[2]->v.f, p[3]->v.f, p[4]->v.f, p[5]->v.f);
}

static void glloadidentity(DaoContext *ctx, DValue *p[], int N) {
    glLoadIdentity();
}

static void glmatrixmode(DaoContext *ctx, DValue *p[], int N) {
    glMatrixMode(p[0]->v.i);
}

static void glclearcolor(DaoContext *ctx, DValue *p[], int N) {
    glClearColor(p[0]->v.f, p[1]->v.f, p[2]->v.f, p[3]->v.f);
}

static void glclear(DaoContext *ctx, DValue *p[], int N) {
    glClear(p[0]->v.i);
}

static void glcleardepth(DaoContext *ctx, DValue *p[], int N) {
    glClearDepth(p[0]->v.f);
}

static void gluperspective(DaoContext *ctx, DValue *p[], int N) {
    gluPerspective(p[0]->v.f, p[1]->v.f, p[2]->v.f, p[3]->v.f);
}

static void glulookat(DaoContext *ctx, DValue *p[], int N) {
    gluLookAt(
        p[0]->v.f, p[1]->v.f, p[2]->v.f,        // Eye
        p[3]->v.f, p[4]->v.f, p[5]->v.f,        // Center
        p[6]->v.f, p[7]->v.f, p[8]->v.f         // Up
    );
}

static void glenable(DaoContext *ctx, DValue *p[], int N) {
    glEnable(p[0]->v.i);
}

static void gldisable(DaoContext *ctx, DValue *p[], int N) {
    glDisable(p[0]->v.i);
}

static void gldepthfunc(DaoContext *ctx, DValue *p[], int N) {
    glDepthFunc(p[0]->v.i);
}

static void gltranslate(DaoContext *ctx, DValue *p[], int N) {
    glTranslatef(p[0]->v.f, p[1]->v.f, p[2]->v.f);
}

static void glrotate(DaoContext *ctx, DValue *p[], int N) {
    glRotatef(p[0]->v.f, p[1]->v.f, p[2]->v.f, p[3]->v.f);
}

static void glscale(DaoContext *ctx, DValue *p[], int N) {
    glScalef(p[0]->v.f, p[1]->v.f, p[2]->v.f);
}

static void glpushmatrix(DaoContext *ctx, DValue *p[], int N) {
    glPushMatrix();
}

static void glpopmatrix(DaoContext *ctx, DValue *p[], int N) {
    glPopMatrix();
}

static void glshademodel(DaoContext *ctx, DValue *p[], int N) {
    glShadeModel(p[1]->v.i);
}

static void glusolidsphere(DaoContext *ctx, DValue *p[], int N) {
    GLUquadricObj *quadObj;

    quadObj = gluNewQuadric();

    gluQuadricDrawStyle(quadObj, GLU_FILL);
    gluQuadricNormals(quadObj, GLU_SMOOTH);
    gluSphere(quadObj, p[0]->v.f, p[1]->v.i, p[2]->v.i);

    gluDeleteQuadric(quadObj);
}

static void glusolidcylinder(DaoContext *ctx, DValue *p[], int N) {
    GLUquadricObj *quadObj;

    quadObj = gluNewQuadric();

    gluQuadricDrawStyle(quadObj, GLU_FILL);
    gluQuadricNormals(quadObj, GLU_SMOOTH);
    gluCylinder(quadObj, p[0]->v.f, p[1]->v.f, p[2]->v.f, p[3]->v.i, p[4]->v.i);

    gluDeleteQuadric(quadObj);
}

static void gllight(DaoContext *ctx, DValue *p[], int N) {
    GLfloat param[] = { p[2]->v.f, p[3]->v.f, p[4]->v.f, p[5]->v.f };

    glLightfv(p[0]->v.i, p[1]->v.i, param);
}

static void glmaterial(DaoContext *ctx, DValue *p[], int N) {
    GLfloat param[] = { p[2]->v.f, p[3]->v.f, p[4]->v.f, p[5]->v.f };

    glMaterialfv(p[0]->v.i, p[1]->v.i, param);
}

static void glnewlist(DaoContext *ctx, DValue *p[], int N) {
    glNewList(p[0]->v.i, p[1]->v.i);
}

static void glendlist(DaoContext *ctx, DValue *p[], int N) {
    glEndList();
}

static void glcalllist(DaoContext *ctx, DValue *p[], int N) {
    glCallList(p[0]->v.i);
}

//

static DaoFuncItem glMeth[] = {
    { glbegin, 		"Begin(mode:int)" },
    { glend, 		"End()" },

    { glcolor, 		"Color(r:float, g:float, b:float)" },
    { glvertex, 	"Vertex(x:float, y:float, z:float = 0.0)" },

    { glviewport, 	"Viewport(x:float, y:float, w:float, h:float)" },
    { glortho, 		"Ortho(left:float, right:float, top:float, bottom:float, near:float, far:float)" },
    { glloadidentity, 	"LoadIdentity()" },
    { glmatrixmode, 	"MatrixMode(mode:int)" },
    { gltranslate, 	"Translate(x:float, y:float, z:float)" },
    { glrotate, 	"Rotate(angle:float, x:float, y:float, z:float)" },
    { glscale, 		"Scale(x:float, y:float, z:float)" },
    { glpushmatrix, 	"PushMatrix()" },
    { glpopmatrix, 	"PopMatrix()" },

    { glclearcolor, 	"ClearColor(r:float, g:float, b:float, a:float = 0.0)" },
    { glclear, 		"Clear(mask:int)" },
    { glcleardepth, 	"ClearDepth(depth:float)" },

    { glenable, 	"Enable(cap:int)" },
    { gldisable, 	"Disable(cap:int)" },
    { gldepthfunc, 	"DepthFunc(func:int)" },

    { glshademodel, 	"ShadeModel(mode:int)" },
    { gllight,		"Light(light:int, pname:int, r:float, g:float, b:float, a:float)" },
    { glmaterial,	"Material(face:int, pname:int, r:float, g:float, b:float, a:float)" },


    { glnewlist, 	"NewList(list:int, mode:int)" },
    { glendlist, 	"EndList()" },
    { glcalllist, 	"CallList(list:int)" },

    { NULL, NULL }
};

static DaoFuncItem gluMeth[] = {
    { gluperspective, 	"Perspective(fovy:float, aspect:float, znear:float, zfar:float)" },
    { glulookat, 	"LookAt(eyeX:float, eyeY:float, eyeZ:float, centerX:float, centerY:float, centerZ:float, upX:float, upY:float, upZ:float)" },

    { glusolidsphere, 	"SolidSphere(radius:float, slices:int, stacks:int)" },
    { glusolidcylinder,	"SolidCylinder(base:float, top:float, height:float, slices:int, stacks:int)" },

    { NULL, NULL }
};

static DaoNumItem glConst[] = {
    /* Primitives */

    { "TRIANGLES", 		DAO_INTEGER, GL_TRIANGLES },
    { "QUADS", 			DAO_INTEGER, GL_QUADS },
    { "POINTS", 		DAO_INTEGER, GL_POINTS },
    { "LINES", 		        DAO_INTEGER, GL_LINES },

    /* Poligons */

    { "FRONT", 		        DAO_INTEGER, GL_FRONT },
    { "BACK", 		        DAO_INTEGER, GL_BACK },
    { "FRONT_AND_BACK",         DAO_INTEGER, GL_FRONT_AND_BACK },

    /* Display lists */

    { "COMPILE", 		DAO_INTEGER, GL_COMPILE },
    { "COMPILE_AND_EXECUTE", 	DAO_INTEGER, GL_COMPILE_AND_EXECUTE },

    /* Matrix mode */

    { "MODELVIEW", 		DAO_INTEGER, GL_MODELVIEW },
    { "PROJECTION", 		DAO_INTEGER, GL_PROJECTION },
    { "TEXTURE", 		DAO_INTEGER, GL_TEXTURE },
    { "COLOR", 			DAO_INTEGER, GL_COLOR },

    /* Clear mask */

    { "COLOR_BUFFER_BIT", 	DAO_INTEGER, GL_COLOR_BUFFER_BIT },
    { "DEPTH_BUFFER_BIT", 	DAO_INTEGER, GL_DEPTH_BUFFER_BIT },
    { "ACCUM_BUFFER_BIT", 	DAO_INTEGER, GL_ACCUM_BUFFER_BIT },
    { "STENCIL_BUFFER_BIT", 	DAO_INTEGER, GL_STENCIL_BUFFER_BIT },

    /* Depth */

    { "DEPTH_TEST", 		DAO_INTEGER, GL_DEPTH_TEST },
    { "LEQUAL", 		DAO_INTEGER, GL_LEQUAL },
    { "CULL_FACE", 		DAO_INTEGER, GL_CULL_FACE },

    /* Light */

    { "LIGHTING", 		DAO_INTEGER, GL_LIGHTING },
    { "LIGHT0", 	        DAO_INTEGER, GL_LIGHT0 },
    { "LIGHT1", 	        DAO_INTEGER, GL_LIGHT1 },
    { "LIGHT2", 	        DAO_INTEGER, GL_LIGHT2 },
    { "LIGHT3", 	        DAO_INTEGER, GL_LIGHT3 },
    { "LIGHT4", 	        DAO_INTEGER, GL_LIGHT4 },
    { "LIGHT5", 	        DAO_INTEGER, GL_LIGHT5 },
    { "LIGHT6", 	        DAO_INTEGER, GL_LIGHT6 },
    { "LIGHT7", 	        DAO_INTEGER, GL_LIGHT7 },
    { "LIGHT_MODEL_AMBIENT", 	DAO_INTEGER, GL_LIGHT_MODEL_AMBIENT },
    { "AMBIENT", 	        DAO_INTEGER, GL_AMBIENT },
    { "AMBIENT_AND_DIFFUSE",    DAO_INTEGER, GL_AMBIENT_AND_DIFFUSE },
    { "DIFFUSE", 	        DAO_INTEGER, GL_DIFFUSE },
    { "SPECULAR", 	        DAO_INTEGER, GL_SPECULAR },
    { "SHININESS", 	        DAO_INTEGER, GL_SHININESS },
    { "POSITION", 	        DAO_INTEGER, GL_POSITION },
    { "NORMALIZE", 	        DAO_INTEGER, GL_NORMALIZE },
    { "SMOOTH", 	        DAO_INTEGER, GL_SMOOTH },
    { "COLOR_MATERIAL", 	DAO_INTEGER, GL_COLOR_MATERIAL },

    { NULL, 0, 0 }
};

DaoTypeBase glTyper = {
    "gl",
    NULL,
    glConst,
    glMeth,               	/* methods */
    { NULL },      		/* parent type */
    { NULL },
    NULL,
    NULL                        /* free by free() */
};

DaoTypeBase gluTyper = {
    "glu",
    NULL,
    NULL,
    gluMeth,               	/* methods */
    { NULL },      		/* parent type */
    { NULL },
    NULL,
    NULL                        /* free by free() */
};
